package com.mw.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONArray;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.*;
import com.deepoove.poi.util.PoitlIOUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.mw.pojo.SysLoginUser;
import com.mw.service.IUserService;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName: ReportController
 * 类文件简单描述:
 * @Author: MW
 * @CreateDate: 2022/2/12 14:08
 */
@Controller
@RequestMapping("/export")
public class ReportController {

    @Autowired
    private IUserService userService;

    //定义全局的字体静态变量
    private static Font titlefont;
    private static Font headfont;
    private static Font keyfont;
    private static Font textfont;

    static {
        try {
            // 不同字体（这里定义为同一种字体：包含不同字号、不同style）
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            titlefont = new Font(bfChinese, 16, Font.BOLD);
            headfont = new Font(bfChinese, 14, Font.BOLD);
            keyfont = new Font(bfChinese, 10, Font.BOLD);
            textfont = new Font(bfChinese, 10, Font.NORMAL);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @GetMapping("/userDataByExcel")
    public void userDataByExcel(@RequestParam(required = false) String condition, HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户明细表", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), SysLoginUser.class).head(SysLoginUser.class).sheet("用户明细表").doWrite(userService.getUserListCondition(condition));
    }

    @GetMapping("/userDataByCSV")
    public void userDataByCSV(@RequestParam(required = false) String condition, HttpServletResponse response) throws Exception {
        response.setContentType("text/csv");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户明细表", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".csv");
        OutputStreamWriter osw = new OutputStreamWriter(response.getOutputStream(), "GBK");
        CSVPrinter csvPrinter = CSVFormat.DEFAULT.withHeader("用户ID", "用户名", "昵称", "性别", "用户类型", "账号状态").print(osw);//如果要展示用户id，表头不能直接写“ID”，因为“ID”字符后不有任何有效的SYLK代码，会导致打开文件时报SYLK错误
        List<SysLoginUser> userListCondition = userService.getUserListCondition(condition);
        for (SysLoginUser user : userListCondition) {
            csvPrinter.printRecord(user.getId(), user.getUsername(), user.getNickname(), user.getGender(), user.getUserType(), user.getStatus());
        }
        csvPrinter.flush();
        csvPrinter.close();
    }

    @GetMapping("/userDataByJSON")
    public void userDataByJSON(@RequestParam(required = false) String condition, HttpServletResponse response) throws Exception {
        response.setContentType("text/javascript");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户明细表", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".json");
        OutputStreamWriter osw = new OutputStreamWriter(response.getOutputStream(), "utf-8");
        String str = JSONArray.toJSON(userService.getUserListCondition(condition)).toString();
        osw.write(str);
        osw.flush();
        osw.close();
    }

    @GetMapping("/userDataByPDF")
    public void userDataByPDF(@RequestParam(required = false) String condition, HttpServletResponse response) throws Exception {
        response.setContentType("application/pdf");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户明细表", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
        Document document = new Document(PageSize.A4);
        PdfWriter.getInstance(document, response.getOutputStream());
        document.addTitle("用户明细表");
        Paragraph paragraph = new Paragraph();//需要初始化一个段落
        document.open();//开始编辑
        PdfPTable table = new PdfPTable(6);//生成一个6列的表格
        table.addCell(createCell("用户ID", keyfont, Element.ALIGN_CENTER));
        table.addCell(createCell("用户名", keyfont, Element.ALIGN_CENTER));
        table.addCell(createCell("昵称", keyfont, Element.ALIGN_CENTER));
        table.addCell(createCell("性别", keyfont, Element.ALIGN_CENTER));
        table.addCell(createCell("用户类型", keyfont, Element.ALIGN_CENTER));
        table.addCell(createCell("账号状态", keyfont, Element.ALIGN_CENTER));
        List<SysLoginUser> userListCondition = userService.getUserListCondition(condition);
        for (SysLoginUser user : userListCondition) {
            table.addCell(createCell(String.valueOf(user.getId()), textfont, Element.ALIGN_CENTER));
            table.addCell(createCell(String.valueOf(user.getUsername()), textfont, Element.ALIGN_CENTER));
            table.addCell(createCell(String.valueOf(user.getNickname()), textfont, Element.ALIGN_CENTER));
            table.addCell(createCell(String.valueOf(user.getGender()), textfont, Element.ALIGN_CENTER));
            table.addCell(createCell(String.valueOf(user.getUserType()), textfont, Element.ALIGN_CENTER));
            table.addCell(createCell(String.valueOf(user.getStatus()), textfont, Element.ALIGN_CENTER));
        }
        document.add(paragraph);
        document.add(table);
        document.close();
    }

    /**
     * 创建单元格
     *
     * @param value 值
     * @param font  字体
     * @param align 水平位置
     * @return
     */
    public PdfPCell createCell(String value, Font font, int align) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(align);
        cell.setPhrase(new Phrase(value, font));
        return cell;
    }

    @GetMapping("/userDataByWORD")
    public void userDataByWORD(@RequestParam(required = false) String condition, HttpServletResponse response) throws Exception {
        List<SysLoginUser> userListCondition = userService.getUserListCondition(condition);
        if (Collections.isEmpty(userListCondition)) {
            return;
        }
        Map<String, Object> downLoadData = Maps.newHashMap();
        List<Map<String, Object>> tableTemplates = Lists.newArrayList();//对应模板中的{{?template}}{{/template}}，区块对标签，在处理一系列文档元素的时候非常有用，位于区块对中的文档元素可以被渲染零次，一次或N次，这取决于区块对的取值
        downLoadData.put("title", Texts.of("用户统计明细").fontSize(18).bold().fontFamily("微软雅黑").create());//对应模板中的{{title}}文本标签
        Map<String, Object> tableTemplate = Maps.newHashMap();//对应区块对标签中的各类元素
        //根据性别进行统计
        tableTemplate.put("content", "用户性别统计");//对应模板中的{{content}}文本标签
        TableRenderData table = Tables.create(null);//初始化一个table
        table.addRow(Rows.of("类别", "小计", "比例").textColor("333333").bgColor("dbdbdb").center().create());//初始化table表头
        //组装表格数据
        String[] statistics = new String[]{"男", "女", "未知"};
        NumberFormat numberFormat = NumberFormat.getInstance();
        numberFormat.setMaximumFractionDigits(2);
        List<Map<String, Object>> listData = Lists.newArrayList();
        for (int i = 0; i < statistics.length; i++) {
            Map<String, Object> map = Maps.newHashMap();
            map.put("gender", statistics[i]);//类别
            int finalI = i;
            int count = userListCondition.stream().filter(m -> m.getGender().equals(statistics[finalI])).collect(Collectors.toList()).size();//当前类别总量
            map.put("count", count);
            map.put("proportion", userListCondition.size() > 0 ? numberFormat.format((float) count / (float) userListCondition.size() * 100) : 0);//比例
            table.addRow(Rows.create(map.get("gender").toString(), map.get("count").toString(), map.get("proportion").toString()));
            listData.add(map);
        }
        //打印listData：[{gender=男, proportion=0, count=0}, {gender=女, proportion=0, count=0}, {gender=未知, proportion=100, count=1}]
        List<Number> proportion = listData.stream().map(m -> Integer.parseInt(String.valueOf(m.get("proportion")))).collect(Collectors.toList());
        Number[] numbers = proportion.toArray(new Number[proportion.size()]);
        ChartSingleSeriesRenderData chart = Charts.ofPie("", statistics).series("countries", numbers).create();//生成饼图
        tableTemplate.put("table", table);
        tableTemplate.put("pieChart", chart);
        tableTemplates.add(tableTemplate);//目前区块对只有性别统计，可以继续添加其他统计维度的报表
        downLoadData.put("template", tableTemplates);
        response.setContentType("application/octet-stream");
        String fileName = URLEncoder.encode("用户统计明细", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".docx");
        XWPFTemplate template = XWPFTemplate.compile("static/template/template.docx").render(downLoadData);
        OutputStream out = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        template.write(bos);
        bos.flush();
        out.flush();
        PoitlIOUtils.closeQuietlyMulti(template, bos, out);
    }
}
